package com.freedom.base.listener;

import com.freedom.auth.domain.Permission;
import com.freedom.auth.service.IPermissionService;
import com.freedom.base.annotation.FreedomPermission;
import com.freedom.base.enums.RequestTypeEnum;
import com.freedom.base.util.ClassUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author freedom
 */
@WebListener
@Transactional
public class PermissionListener implements ServletContextListener {
    @Value("${freedom.permission.scan-package}")
    private String url;

    @Autowired
    private IPermissionService permissionService;

    @Override
    public void contextInitialized ( ServletContextEvent sce ) {
        // 清空权限表
        permissionService.clear();
        System.out.println("监听器初始化。。。。");
        List<Class> allClassName = ClassUtils.getAllClassName(url);
        //allClassName.forEach(System.out::println);

        /**
         * 1、获取每一个FreedomPermission注解,确定是否有权限
         * 2、，如果有权限，
         *      2.1、判断 拼接url requestMappingUrl + MethodUrl
         *       没有就跳过
         *  3、测试方法中有无权限
         *  4、封装对象
         */

        for (Class aClass : allClassName) {
            FreedomPermission annotation = (FreedomPermission) aClass.getAnnotation(FreedomPermission.class);

            if (!Objects.nonNull(annotation)) {
                // 为空，无权限 跳过本次循环，进入下一次
                continue;
            }
            // 不为空 有权限 拼接url
            RequestMapping reqMappingAnnotation = (RequestMapping) aClass.getAnnotation(RequestMapping.class);
            // 父权限路径
            String parentUrl = reqMappingAnnotation.value()[0];

            // 封装parent对象
            // Permission对象父对象
            Permission parent = new Permission();
            parent.setUrl(parentUrl);
            parent.setDescs(annotation.descs());
            parent.setName(annotation.name());
            parent.setSn(aClass.getSimpleName());

            // 父权限 入库
            permissionService.insert(parent);

            Method[] methods = aClass.getMethods();
            for (Method method : methods) {
                FreedomPermission methodAnnotation = method.getAnnotation(FreedomPermission.class);
                if (!Objects.nonNull(methodAnnotation)) {
                    // 方法中无权限
                    continue;
                }
                // 有权限 获取url
                // 方法中的url
                String methodUrl = getMethodUrl(method);
                // 封装对象
                Permission permission = new Permission();
                permission.setName(methodAnnotation.name());
                permission.setParent(parent);
                permission.setUrl(parentUrl + methodUrl);
                permission.setDescs(methodAnnotation.descs());
                String sn = aClass.getSimpleName() + ":" + method.getName();
                permission.setSn(sn);

                // 入库
                permissionService.insert(permission);
            }
        }
        System.out.println("监听器结束。。。。。");
    }

    public String getMethodUrl ( Method method ) {
        String methodUrl = "";
        // 取枚举中定义的所有的请求类型
        RequestTypeEnum[] requestTypeEnums = RequestTypeEnum.values();
        for (RequestTypeEnum typeEnum : requestTypeEnums) {
            // 根据枚举中的不同的请求类型的class获取该类型对应的注解对象
            Annotation annotation = method.getAnnotation(typeEnum.getRequestType());
            // 如果该请求类型注解不存在就跳过
            if (Objects.isNull(annotation)) {
                continue;
            }
            try {
                // 如果该请求类型注解存在,就获取它里面的value方法
                Class<? extends Annotation> aClass = annotation.annotationType();
                Method annotationMethod = aClass.getMethod("value");
                // 通过invoke调用该对象的value方法,获取结果
                // 反射执行 方法 方法名.invoke(对象)
                String[] value = (String[]) annotationMethod.invoke(annotation);
                // 如果value不为空且长度大于0,就赋值给methodUrl,并跳出循环
                if (value != null && value.length > 0) {
                    methodUrl = value[0];
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }
        return methodUrl;
    }
}
